﻿using System;
using System.Threading;
using System.Windows.Input;
using Hopscotch.Common.Logging;
using Hopscotch.Presentation.Common;
using Hopscotch.Presentation.Common.Utils;
using Hopscotch.Presentation.DiagnosticsModule.Constants;
using Hopscotch.Presentation.DiagnosticsModule.Models;
using Microsoft.Practices.Prism.Commands;

namespace Hopscotch.Presentation.DiagnosticsModule.ViewModels
{
    public class SystemDiagnosticsViewModel : ViewModelBase, IDisposable
    {
        private ILogger logger;
        private Timer timer;
        public SystemDiagnosticsModel Model { get; private set; }

        // Track whether Dispose has been called.
        private bool disposed = false;

        public ICommand GcCollectCommand { get; private set; }

        public SystemDiagnosticsViewModel()
        {
            logger = AppLogger.CreateLogger<SystemDiagnosticsViewModel>();

            //Update this here as we are interested in the vm's thread, not the timers
            int threadId = Thread.CurrentThread.ManagedThreadId;
            this.Model = new SystemDiagnosticsModel(threadId);

            this.ViewTitle = "Diagnostics";
            this.Icon16Uri = new Uri(IconPaths.Wrench16);

            GcCollectCommand = new DelegateCommand(GcCollect);
        }

        private void TimerCallback(object state)
        {
            Model.Update();
        }

        public void StartMemoryTracking()
        {
            timer = new Timer(TimerCallback, null, Timeout.Infinite, Timeout.Infinite);
            timer.Change(0, 1000);
        }

        public void StopMemoryTracking()
        {
            if (timer != null)
            {
                timer.Change(Timeout.Infinite, Timeout.Infinite);
            }
        }

        public override void OnValidate()
        {
        }

        private void GcCollect()
        {
            logger.Debug("GC.Collect explicit call");
            GC.Collect();
        }

        // Implement IDisposable.
        // Do not make this method virtual.
        // A derived class should not be able to override this method.
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SupressFinalize to
            // take this object off the finalization queue
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }


        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this.disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                if (disposing && timer != null)
                {
                    // Dispose managed resources.
                    timer.Dispose();
                }

                // Call the appropriate methods to clean up
                // unmanaged resources here.

                // Note disposing has been done.
                disposed = true;
            }
        }

        // Use C# destructor syntax for finalization code.
        // This destructor will run only if the Dispose method
        // does not get called.
        // It gives your base class the opportunity to finalize.
        // Do not provide destructors in types derived from this class.
        ~SystemDiagnosticsViewModel()
        {
            Dispose(false);
        }

    }
}
